<?php
/**
 * 第三方服务监控系统
 */
namespace App\Repositories;


use App\Console\Commands\Export\export;
use App\Enums\AccountCheckEnum;
use App\Exceptions\BasicException;
use App\Models\MainDB\AccountLog;
use App\Models\MainDB\Gift;
use App\Models\MainDB\GiftBackpack;
use App\Models\MainDB\User;
use App\Services\Tools\CurlService;
use App\Services\Tools\RongCloudService;
use App\Services\Tools\ShuMeiService;
use App\Services\Tools\SmsService;
use App\Services\Tools\ZegoService;
use Illuminate\Support\Facades\DB;
use function Complex\argument;

class ThreeServiceCheckRepository
{
    //正式
    const PRO_ROOM_ID = 51; //正式示例 即构房间id
    const PRO_USER_ID = 547900; //正式示例 融云用户id
    //非正式
    const TEST_ROOM_ID = 20391; //即构房间id
    const TEST_USER_ID = 547900; //融云用户id

//    const CHECK_TEXT = '气泡星球';  //正式示例 数美校验内容
    const CHECK_TEXT = '测试';  //正式示例 数美校验内容
    const ZEGO_HOST = 'https://rtc-api.zego.im/';
    const RY_HOST = "http://api-cn.ronghub.com/user/info.json";
    const CURL_MAX_TIME = 5;   //最大CURL时间

    const MIN_CURL_WARNING_TIME = 2000;
    const MIN_CURL_ERROR_TIME = 5000;

    const SEND_MSG_TTL = 14400; //最小发短信间隔4小时

    const ZEGO = 1;
    const RY=2;
    const SHUMEI = 3;

    private $roomId;
    private $userId;

    public function __construct()
    {
        $isPro = env('APP_ENV')=='production'?1:0;
        if($isPro){
            $this->roomId = self::PRO_ROOM_ID;
            $this->userId = self::PRO_USER_ID;
        }else{
            $this->roomId = self::TEST_ROOM_ID;
            $this->userId = self::TEST_USER_ID;
        }
    }
    //日志记录
    public function getRecordLogList($type,$page,$pageSize,$param){
        if($type == self::RY){
            $model = app('model_three_check_ry');
        }else if($type == self::ZEGO){
            $model = app('model_three_check_zego');
        }else if($type == self::SHUMEI){
            $model = app('model_three_check_shumei');
        }else{
            throw new BasicException(0, '不支持的类型');
        }
        $where=[];
        if(isset($param['is_out_time'])){
            if ($param['is_out_time'] == 1) {
                $where['is_out_time'] = $param['is_out_time'];
            } else {
                $where[] = ['is_out_time', '!=', 1];
            }
        }
        if(isset($param['record_type'])){
            $where['record_type']=$param['record_type'];
        }
        if(isset($param['min_use_time'])){
            $where[]=['use_time','>=',$param['min_use_time']];
        }
        if(isset($param['max_use_time'])){
            $where[]=['use_time','<=',$param['max_use_time']];
        }
        $list = $model->where($where)->orderBy('id','desc')
            ->paginate($pageSize, ['*'], '', $page);
        $list = empty($list)?[]:$list->toArray();
        return [
            'total' => $list['total'],
            'list' => $list['data']
        ];
    }


    /**
     * 即构服务校验
     * author Hso
     */
    public function zegoServiceCheck($recordType=1){
        $curlHost = self::ZEGO_HOST.'?Action=DescribeSimpleStreamList'; //即构文档地址 https://doc-zh.zego.im/article/11662
        $beginTime = get_microtime();
        $originData = (new ZegoService())->getSimpleStreamList($this->roomId,$curlHost,self::CURL_MAX_TIME);
        $endTime = get_microtime();
        $data = [
            'status' => 1,
            'origin_data' => json_encode($originData),
            'record_type' => $recordType,
            'use_time' => $endTime-$beginTime,
        ];
        if(empty($originData) || $originData['code']!=200){
            $data['status'] = 2;
        }
        $insertDbRes = $this->insertCheckData($data,self::ZEGO);
        return [
            'data' => $data,
            'originData' => $originData,
            'insertDbRes' => $insertDbRes,
        ];
    }

    /**
     * 融云服务校验
     * author Hso
     */
    public function ryServiceCheck($recordType=1){
        $beginTime = get_microtime();
        $originData = (new RongCloudService())->getUserInfo($this->userId,self::RY_HOST);
        $endTime = get_microtime();
        $data = [
            'status' => 1,
            'origin_data' => json_encode($originData),
            'record_type' => $recordType,
            'use_time' => $endTime-$beginTime,
        ];
        if(empty($originData) || $originData['code']!=200){
            $data['status'] = 2;
        }
        $insertDbRes = $this->insertCheckData($data,self::RY);
        return [
            'data' => $data,
            'originData' => $originData,
            'insertDbRes' => $insertDbRes,
        ];
    }
    //插入数据
    public function insertCheckData($data,$type){
        $isOutTime = $data['use_time']>=self::MIN_CURL_ERROR_TIME?3:($data['use_time']>=self::MIN_CURL_WARNING_TIME?2:1);
        $data['is_out_time'] = $isOutTime;
        if($type == self::RY){
            app('model_three_check_ry')->insert($data);
        }else if($type == self::ZEGO){
            app('model_three_check_zego')->insert($data);
        }else if($type == self::SHUMEI){
            app('model_three_check_shumei')->insert($data);
        }
        $data['server_type'] = $type;
        app('model_three_check')->insert($data);
        $sendMsgRes = [];
        if($isOutTime>1){
            $sendMsgRes = $this->sendMsg($data,$type);
        }
        return [
            'isOutTime' => $isOutTime,
            'sendMsgRes' => $sendMsgRes,
        ];
    }
    //出现问题通知管理员
    public function sendMsg($data,$type){
        $isClose =  app('redis')->get('three:send:is:close:'.$type);
        if(!empty($isClose)){
            return [
                'msg' => '发送渠道已关闭',
                'isSendMsg' => false,
            ];
        }
        $lastSendTime = app('redis')->get('three:error:msg:time:'.$type);
        if(time()-$lastSendTime<self::SEND_MSG_TTL){
            return [
                'msg' => '未到发送间隔',
                'isSendMsg' => false,
            ];
        }
        $typeName = $this->typeToName($type);
        $msg = " ".$typeName."服务异常,响应时间为".$data['use_time'].'ms ';
        app('redis')->set('three:error:msg:time:'.$type,time());
        $sendPhones = app('model_config')->getValue('THREE_SERVER_NOTICE_PHONES');
        $sendPhones = explode(',',$sendPhones);
        $allNum = $successNum =  0;
        if(!empty($sendPhones)){
            foreach ($sendPhones as $v){
                $res = SmsService::sentryThreeToUser($msg,$v);
                $allNum++;
                if($res){
                    $successNum ++;
                }
            }
        }
        return [
            'allNum' => $allNum,
            'msg' => '成功',
            'isSendMsg' => true,
            'successNum' => $successNum,
        ];
    }

    private function typeToName($type){
        if($type == self::RY){
            return '融云';
        }else if($type == self::ZEGO){
            return '即构';
        }else if($type == self::SHUMEI){
            return '数美';
        }
        return  '';
    }
    //发送短信是否开启
    public function setSenMsgIsClose($type,$isClose=0){
        if(in_array($type,[
                self::RY,self::ZEGO,self::SHUMEI
            ])){
            $key = "three:send:is:close:".$type;
        }else{
            throw new BasicException(0, '不支持的类型');
        }
        app('redis')->set($key,$isClose);
    }

    //手动校验
    public function manualCheck($type){
        if($type == self::RY){
            $checkRes = $this->ryServiceCheck(2);
        }else if($type == self::ZEGO){
            $checkRes = $this->zegoServiceCheck(2);
        }else if($type == self::SHUMEI){
            $checkRes = $this->shuMeiServiceCheck(2);
        }else{
            throw new BasicException(0, '不支持的类型');
        }
        $checkRes['is_out_time'] = $checkRes['insertDbRes']['isOutTime'];

        return $checkRes;
    }

    /**
     * 数美服务校验
     * author Hso
     */
    public function shuMeiServiceCheck($recordType=1){
        $beginTime = get_microtime();
        $ext = ['channel' => 'GROUP_CHAT', 'room_id' => $this->roomId];
        $originData = (new ShuMeiService())->checkTextApi(self::CHECK_TEXT,$this->userId,$ext,self::CURL_MAX_TIME);
        $endTime = get_microtime();
        $data = [
            'status' => 1,
            'origin_data' => json_encode($originData),
            'record_type' => $recordType,
            'use_time' => $endTime-$beginTime,
        ];
        if(empty($originData) || $originData['code']!=200){
            $data['status'] = 2;
        }
        $insertDbRes = $this->insertCheckData($data,self::SHUMEI);
        return [
            'data' => $data,
            'originData' => $originData,
            'insertDbRes' => $insertDbRes,
        ];
    }

    public function adminStat(){
        $ry = $this->threeTypeStat(self::RY);
        $zego = $this->threeTypeStat(self::ZEGO);
        $shumei = $this->threeTypeStat(self::SHUMEI);
        $res =  [
            $ry,
            $zego,
            $shumei
        ];
        return $res;
    }
    //对应类型第三方统计
    public function threeTypeStat($type){
        if($type == self::RY){
            $model = app('model_three_check_ry');
            $serverName = '融云';
            $serverType = $type;
        }else if($type == self::ZEGO){
            $model = app('model_three_check_zego');
            $serverName = '即构';
            $serverType = $type;
        }else if($type == self::SHUMEI){
            $model = app('model_three_check_shumei');
            $serverName = '数美';
            $serverType = $type;
        }

        $lastMsg = $model->orderBy('id','desc')->first();
        $sendRecord = $model->groupBy('is_out_time')->select(DB::raw('count(*) as ct'),'is_out_time')->get();
        $lastError =  $model->where('is_out_time',2)->orderBy('id','desc')->first();

        $sumCostTimer = $model->sum('use_time');
        $lastMsg = empty($lastMsg)?[]:$lastMsg->toArray();
        $lastError = empty($lastError)?[]:$lastError->toArray();
        $allNum = $errorNum = $warningNum = 0;
        foreach ($sendRecord as $v){
            $allNum += $v['ct'];
            if($v['is_out_time'] == 2){
                $warningNum += $v['ct'];
            }
            if($v['is_out_time'] == 3){
                $errorNum += $v['ct'];
            }
        }
        if($allNum<=0){
            $averageCostTime = 0;
            $rightPercent = $warningPercent = $errorPercent = 0;
        }else{
            $averageCostTime = intval($sumCostTimer/$allNum)/1000;
            $rightPercent = round(($allNum-$errorNum-$warningNum)/$allNum,4);
            $warningPercent = round($warningNum/$allNum/100,4);
            $errorPercent = round($errorNum/$allNum/100,4);
        }
        $isCloseSendMsg = app('redis')->get("three:send:is:close:".$type);
        return [
            'server_name' => $serverName,
            'is_close' => $isCloseSendMsg?1:0,
            'server_type' => $serverType,
            'is_error' => empty($lastMsg)?0:($lastMsg['is_out_time']>2?1:0),
            'right_percent' => $rightPercent,
            'warning_percent' => $warningPercent,
            'error_percent' => $errorPercent,
            'all_num' => $allNum,
            'error_num' => $errorNum,
            'warning_num' => $warningNum,
            'last_error' => $lastError,
            'average_cost_time' => $averageCostTime,
        ];
    }
}
